package patern;

import java.util.TreeMap;

import engine.expression.Constante;
import engine.expression.Expression;
import engine.expression.Operator;

public class Rewriter
{
	private Patern patern;
	private Patern rewritingPatern;
	private TreeMap<String, Constante> valuation;
	
	public Rewriter(Patern patern, Patern rewritingPatern)
	{
		this.patern = patern;
		this.rewritingPatern = rewritingPatern;
		valuation = new TreeMap<String, Constante>();
	}
	
	public Expression filter(Expression exp)
	{
		if(filter(exp, patern))
		{
			return makeExpression(rewritingPatern);
		}
		else
			return null;
	}

	private boolean filter(Expression exp, Patern patern)
	{
		if(patern.isLeaf())
		{
			if(exp.isConstante())
			{
				if(valuation.containsKey(patern.name()))
					return match((Constante)exp, valuation.get(patern.name()));
				else
				{
					valuation.put(patern.name(), (Constante)exp);
					return true;
				}
			}
			else
				return false;
		}
		
		if(patern.operator() != exp.operator())
			return false;
		else
		{
			boolean leftRes = true;
			
			if(patern.left() != null)
			{
				if(exp.left() != null)
					leftRes = filter(exp.left(), patern.left());
				else
					return false;
			}
			
			if(leftRes)
			{
				if(patern.right() != null)
				{
					if(exp.right() != null)
						return filter(exp.right(), patern.left());
					else
						return false;
				}
			}
			
			return leftRes;
		}
	}
	
	private Expression makeExpression(Patern p)
	{
		if(p.isLeaf())
		{
			if(p.name() != null)
				return new Constante(valuation.get(p.name()).value());
			else
				return new Constante(p.value());
		}
		else
		{
			Expression left = null, right = null;
			
			if(p.left() != null)
				left = makeExpression(p.left());
			
			if(p.right() != null)
				right = makeExpression(p.right());
				
			return new Operator(p.operator(), left, right);
		}
			
	}

	private boolean match(Constante exp, Constante val)
	{
		return exp.name() == val.name() || exp.value() == val.value();
	}
}
